export class XmlUtil {
  /**
   * 解析XML字符串中的标签值
   * @param xml XML字符串
   * @param tagName 标签名
   * @returns 标签内容，未找到则返回undefined
   */
  public static getTagValue(xml: string, tagName: string): string | undefined {
    const regex = new RegExp(`<${tagName}>(.*?)<\/${tagName}>`, 's');
    const match = xml.match(regex);
    return match ? match[1].trim() : undefined;
  }

  /**
   * 从XML字符串中提取所有匹配特定标签的内容
   * @param xml XML字符串
   * @param tagName 标签名
   * @returns 匹配到的所有标签内容数组
   */
  public static getAllTagValues(xml: string, tagName: string): string[] {
    const regex = new RegExp(`<${tagName}>(.*?)<\/${tagName}>`, 'gs');
    const matches = [...xml.matchAll(regex)];
    return matches.map(match => match[1].trim());
  }

  /**
   * 提取XML标签的属性值
   * @param xml XML字符串
   * @param tagName 标签名
   * @param attributeName 属性名
   * @returns 属性值，未找到则返回undefined
   */
  public static getAttributeValue(xml: string, tagName: string, attributeName: string): string | undefined {
    const regex = new RegExp(`<${tagName}[^>]*${attributeName}="([^"]*)"[^>]*>`, 'i');
    const match = xml.match(regex);
    return match ? match[1] : undefined;
  }

  /**
   * 通过路径获取XML中的值
   * @param xml XML字符串
   * @param path 路径，例如 "root.parent.child"
   * @param defaultValue 未找到时的默认值
   * @returns 找到的值或默认值
   */
  public static getValueByPath<T>(xml: string, path: string, defaultValue: T): T {
    const tags = path.split('.');
    let currentXml = xml;
    
    for (let i = 0; i < tags.length; i++) {
      const tag = tags[i];
      
      // 检查是否是最后一个标签
      if (i === tags.length - 1) {
        const value = this.getTagValue(currentXml, tag);
        return value !== undefined ? value as unknown as T : defaultValue;
      }
      
      // 提取当前标签的内容作为新的XML上下文
      const content = this.getTagValue(currentXml, tag);
      if (content === undefined) {
        return defaultValue;
      }
      
      currentXml = content;
    }
    
    return defaultValue;
  }

  /**
   * 通过路径获取XML属性值
   * @param xml XML字符串
   * @param path 路径，例如 "root.parent.child@attribute"
   * @param defaultValue 未找到时的默认值
   * @returns 找到的属性值或默认值
   */
  public static getAttributeByPath<T>(xml: string, path: string, defaultValue: T): T {
    // 分离属性名
    const parts = path.split('@');
    if (parts.length !== 2) {
      return defaultValue;
    }
    
    const tagPath = parts[0];
    const attributeName = parts[1];
    
    // 如果路径中有多个标签
    if (tagPath.includes('.')) {
      const tags = tagPath.split('.');
      const lastTag = tags.pop() || '';
      const parentPath = tags.join('.');
      
      // 先获取父元素内容
      const parentContent = this.getValueByPath(xml, parentPath, '');
      if (!parentContent) {
        return defaultValue;
      }
      
      // 从父元素内容中查找属性
      const attrValue = this.getAttributeValue(parentContent, lastTag, attributeName);
      return attrValue !== undefined ? attrValue as unknown as T : defaultValue;
    } else {
      // 直接获取属性
      const attrValue = this.getAttributeValue(xml, tagPath, attributeName);
      return attrValue !== undefined ? attrValue as unknown as T : defaultValue;
    }
  }

  /**
   * 简单XML转JSON对象
   * @param xml 简单的XML字符串
   * @returns 转换后的JSON对象
   */
  public static toJson(xml: string): Record<string, any> {
    const result: Record<string, any> = {};
    
    // 移除XML声明和注释
    xml = xml.replace(/<\?xml.*?\?>/g, '').replace(/<!--[\s\S]*?-->/g, '');
    
    // 简单解析标签和值
    const tagRegex = /<([^\s/>]+)[^>]*>([\s\S]*?)<\/\1>/g;
    let match;
    
    while ((match = tagRegex.exec(xml)) !== null) {
      const tagName = match[1];
      const content = match[2].trim();
      
      // 检查内容是否还包含其他标签
      if (/<[^\s/>]+[^>]*>[\s\S]*?<\/[^\s/>]+>/g.test(content)) {
        // 递归解析嵌套内容
        result[tagName] = this.toJson(content);
      } else {
        result[tagName] = content;
      }
    }
    
    return result;
  }

  /**
   * 验证XML字符串是否格式正确
   * @param xml XML字符串
   * @returns 是否有效
   */
  public static isValid(xml: string): boolean {
    try {
      const parser = new DOMParser();
      const doc = parser.parseFromString(xml, 'application/xml');
      // 检查是否有解析错误
      const parserError = doc.querySelector('parsererror');
      return !parserError;
    } catch (error) {
      return false;
    }
  }
}
